package com.efrei.schoolmanager.model.dao;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.AbstractEntityPersister;

/**
 * implémentation générique pour une communication avec hibernate.
 * 
 * @param <T>
 */
public class HibernateDAO<T> {

	private final Session session;
	private final Class<T> type;

	public HibernateDAO(Session session, Class<T> type) {
		this.session = session;
		this.type = type;
	}

	/**
	 * recupére le contenu en base pour la requete hql donnée. Si erreur,
	 * rollback et retourne l'exception. Si requete avec arguments, mieux vaut
	 * la faire soit même ou voir Criteria
	 * 
	 * @param hqlRequest
	 * @return List filtré par la requete hql
	 * @throws HibernateException
	 */
	@SuppressWarnings("unchecked")
	protected List<T> content(String hqlRequest) throws HibernateException {
		return session.createQuery(hqlRequest).list();
	}

	/**
	 * creer un objet en base, rollback si echec
	 * 
	 * @param obj
	 * @return id de l'objet en base
	 * @throws HibernateException
	 */
	public int create(T obj) throws HibernateException {
		return (Integer) session.save(obj);
	}

	/**
	 * update un objet en base
	 * 
	 * @param obj
	 * @throws HibernateException
	 */
	public void update(T obj) throws HibernateException {
		session.update(obj);
	}

	/**
	 * detruit un objet en base, rollback si echec
	 * 
	 * @param obj
	 * @return
	 * @throws HibernateException
	 */
	public void delete(T obj) throws HibernateException {
		session.delete(obj);
	}

	/**
	 * ajoutera ou editera l'objet selon si il est ou non en base
	 * 
	 * @param obj
	 * @throws HibernateException
	 */
	public void saveOrUpdate(T obj) throws HibernateException {
		session.saveOrUpdate(obj);
	}

	/**
	 * reattach l'objet en parametre à la session courante
	 * 
	 * @param obj
	 * @return l'objet réattaché à la session
	 * @throws HibernateException
	 * @throws LazyInitializationException
	 */
	public T reattachToSession(T obj) throws HibernateException,
			LazyInitializationException {
		// update pour en même temps check l'etat en base de la donnée. lock
		// pour donnée sure d'etre bonne
		session.update(obj);
		return obj;
	}

	/**
	 * retourne la meme casse que dans le hbm.xml => USELESS
	 * 
	 * @return nom de la table en base
	 */
	public String getTableName() {
		ClassMetadata hibernateMetadata = session.getSessionFactory()
				.getClassMetadata(type);
		if (!(hibernateMetadata instanceof AbstractEntityPersister)) {
			throw new IllegalArgumentException(
					"classe invalide pour obtenir le nom d'une table");
		}
		return ((AbstractEntityPersister) hibernateMetadata).getTableName();
	}

	public Class<T> getType() {
		return type;
	}

	public Session getSession() {
		return session;
	}
}
